package com.database.interceptor;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.plugins.InterceptorIgnoreHelper;
import com.baomidou.mybatisplus.core.toolkit.PluginUtils;
import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor;
import com.rent.common.utils.ContextUtil;
import com.database.utils.ReplaceSqlUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;

import java.sql.Connection;

/**
 * @author zn
 * @Date 2021/8/26
 */
@Slf4j
public class SchemaInterceptor implements InnerInterceptor {

    private final String tenantDatabasePrefix;

    public SchemaInterceptor(String tenantDatabasePrefix) {
        this.tenantDatabasePrefix = tenantDatabasePrefix;
    }

    protected String changeTable(String sql) {
        // 想要 执行sql时， 不切换到 指定 库, 请直接返回null
        String tenantCode = ContextUtil.getTenant();
        if (StrUtil.isEmpty(tenantCode)) {
            return sql;
        }
        // 拼接数据库前缀 + 租户
        String schemaName = StrUtil.format("{}_{}", tenantDatabasePrefix, tenantCode);
        // 想要 执行sql时， 切换到 切换到自己指定的库， 直接修改 setSchemaName
        return ReplaceSqlUtil.replaceSql(schemaName, sql);
    }

    @Override
    public void beforePrepare(StatementHandler sh, Connection connection, Integer transactionTimeout) {
        // 统一交给 beforePrepare 处理,防止某些sql解析不到，又被beforePrepare重复处理
        PluginUtils.MPStatementHandler mpSh = PluginUtils.mpStatementHandler(sh);
        MappedStatement ms = mpSh.mappedStatement();
        SqlCommandType sct = ms.getSqlCommandType();
        if (sct == SqlCommandType.INSERT || sct == SqlCommandType.UPDATE || sct == SqlCommandType.DELETE || sct == SqlCommandType.SELECT) {
            if (InterceptorIgnoreHelper.willIgnoreDynamicTableName(ms.getId())) {
                return;
            }
            PluginUtils.MPBoundSql mpBs = mpSh.mPBoundSql();
            log.info("sql替换前执行准备: {}", mpBs.sql());
            mpBs.sql(this.changeTable(mpBs.sql()));
        }
    }
}
